<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Test javascript</title>
</head>
<script>
/*
	Base, version 1.0.2
	Copyright 2006, Dean Edwards
	License: http://creativecommons.org/licenses/LGPL/2.1/
*/

var Base = function() {
	if (arguments.length) {
		if (this == window) { // cast an object to this class
			Base.prototype.extend.call(arguments[0], arguments.callee.prototype);
		} else {
			this.extend(arguments[0]);
		}
	}
};

Base.version = "1.0.2";

Base.prototype = {
	extend: function(source, value) {
		var extend = Base.prototype.extend;
		if (arguments.length == 2) {
			var ancestor = this[source];
			// overriding?
			if ((ancestor instanceof Function) && (value instanceof Function) &&
				ancestor.valueOf() != value.valueOf() && /\bbase\b/.test(value)) {
				var method = value;
			//	var _prototype = this.constructor.prototype;
			//	var fromPrototype = !Base._prototyping && _prototype[source] == ancestor;
				value = function() {
					var previous = this.base;
				//	this.base = fromPrototype ? _prototype[source] : ancestor;
					this.base = ancestor;
					var returnValue = method.apply(this, arguments);
					this.base = previous;
					return returnValue;
				};
				// point to the underlying method
				value.valueOf = function() {
					return method;
				};
				value.toString = function() {
					return String(method);
				};
			}
			return this[source] = value;
		} else if (source) {
			var _prototype = {toSource: null};
			// do the "toString" and other methods manually
			var _protected = ["toString", "valueOf"];
			// if we are prototyping then include the constructor
			if (Base._prototyping) _protected[2] = "constructor";
			for (var i = 0; (name = _protected[i]); i++) {
				if (source[name] != _prototype[name]) {
					extend.call(this, name, source[name]);
				}
			}
			// copy each of the source object's properties to this object
			for (var name in source) {
				if (!_prototype[name]) {
					extend.call(this, name, source[name]);
				}
			}
		}
		return this;
	},

	base: function() {
		// call this method from any other method to invoke that method's ancestor
	}
};

Base.extend = function(_instance, _static) {
	var extend = Base.prototype.extend;
	if (!_instance) _instance = {};
	// build the prototype
	Base._prototyping = true;
	var _prototype = new this;
	extend.call(_prototype, _instance);
	var constructor = _prototype.constructor;
	_prototype.constructor = this;
	delete Base._prototyping;
	// create the wrapper for the constructor function
	var klass = function() {
		if (!Base._prototyping) constructor.apply(this, arguments);
		this.constructor = klass;
	};
	klass.prototype = _prototype;
	// build the class interface
	klass.extend = this.extend;
	klass.implement = this.implement;
	klass.toString = function() {
		return String(constructor);
	};
	extend.call(klass, _static);
	// single instance
	var object = constructor ? klass : _prototype;
	// class initialisation
	if (object.init instanceof Function) object.init();
	return object;
};

Base.implement = function(_interface) {
	if (_interface instanceof Function) _interface = _interface.prototype;
	this.prototype.extend(_interface);
};
</script>
<script>
// sprintf() implementation for javascript
// wonghang: I copied it from http://jan.moesen.nu/code/javascript/sprintf-and-printf-in-javascript/,
//           the page said it is in Public Domain, so it is free to use
function sprintf()
{
	if (!arguments || arguments.length < 1 || !RegExp)
	{
		return;
	}
	var str = arguments[0];
	var re = /([^%]*)%('.|0|\x20)?(-)?(\d+)?(\.\d+)?(%|b|c|d|u|f|o|s|x|X)(.*)/;
	var a = b = [], numSubstitutions = 0, numMatches = 0;
	while (a = re.exec(str))
	{
		var leftpart = a[1], pPad = a[2], pJustify = a[3], pMinLength = a[4];
		var pPrecision = a[5], pType = a[6], rightPart = a[7];
		
		//alert(a + '\n' + [a[0], leftpart, pPad, pJustify, pMinLength, pPrecision);

		numMatches++;
		if (pType == '%')
		{
			subst = '%';
		}
		else
		{
			numSubstitutions++;
			if (numSubstitutions >= arguments.length)
			{
				alert('Error! Not enough function arguments (' + (arguments.length - 1) + ', excluding the string)\nfor the number of substitution parameters in string (' + numSubstitutions + ' so far).');
			}
			var param = arguments[numSubstitutions];
			var pad = '';
				   if (pPad && pPad.substr(0,1) == "'") pad = leftpart.substr(1,1);
			  else if (pPad) pad = pPad;
			var justifyRight = true;
				   if (pJustify && pJustify === "-") justifyRight = false;
			var minLength = -1;
				   if (pMinLength) minLength = parseInt(pMinLength);
			var precision = -1;
				   if (pPrecision && pType == 'f') precision = parseInt(pPrecision.substring(1));
			var subst = param;
				   if (pType == 'b') subst = parseInt(param).toString(2);
			  else if (pType == 'c') subst = String.fromCharCode(parseInt(param));
			  else if (pType == 'd') subst = parseInt(param) ? parseInt(param) : 0;
			  else if (pType == 'u') subst = Math.abs(param);
			  else if (pType == 'f') subst = (precision > -1) ? Math.round(parseFloat(param) * Math.pow(10, precision)) / Math.pow(10, precision): parseFloat(param);
			  else if (pType == 'o') subst = parseInt(param).toString(8);
			  else if (pType == 's') subst = param;
			  else if (pType == 'x') subst = ('' + parseInt(param).toString(16)).toLowerCase();
			  else if (pType == 'X') subst = ('' + parseInt(param).toString(16)).toUpperCase();
		}
		str = leftpart + subst + rightPart;
	}
	return str;
}
function output(str)
{
	var obj = document.getElementById('output');
	
	if(!obj) alert('getElementById does not work');
	obj.innerHTML += str;
	obj.innerHTML += "<br />";
	return obj;
}
function testfun(name,fun)
{
	try {
		var msg;
		msg = fun();
		if(msg) output(sprintf('%s OK: %s',name,msg));
		else output(sprintf('%s OK',name));
	}
	catch(e) {
		output(sprintf('%s fail',name));
	}
}
function testBase()
{
	output('<b>Test Base object</b>');

	var Foo = Base.extend({
		value: 123,
		constructor: function() {
			output('Base: Foo constructor OK.');
		},
		test1: function(n) {
			return (n+this.value);
		},
		test2: function(n) {
			return 'test2=' + this.test1(n);
		}
	});
	var Foo2 = Foo.extend({
		constructor: function()	{
			this.base();
			output('Base: Foo2 constructor OK.');
		},
		test1: function(n) {
			return (n-this.value);
		}
	});
	
	try {
		var foo1 = new Foo(); 
		var foo2 = new Foo2();
		
		// test call function
		if(foo1.test1(321) == 444 &&
		   foo1.test2(321) == 'test2=444') output('Base: call function OK.');
		else output('Base: call function fail');
		// test variable
		if(foo1.value == 123) output('Base: get variable OK.');
		else output('Base: get variable fail');
		// modify variable
		foo1.value = 321;
		if(foo1.value == 321) output('Base: modify variable OK.');
		else output('Base: modify variable fail');
		// test inheritance
		if(foo2.test2(123) == 'test2=0') output('Base: class inheritance OK.');
		else output('Base: class inheritance fail');
	}
	catch(e) {
		output(sprintf('Base: fail: %s',e));
	}
}
function testjs()
{
	output('<b>Test javascript</b>');

	testfun('for(var key in foo)', function() {
		var foo = { 
			'one': 1,
			'two': 2,
			'three': 3
		};
		var str;

		str = '';
		for(var key in foo) {
			str += sprintf('%s=%d ',key,foo[key]);
		} 
		return str;
// 	});
}
function testDOM()
{
	output('<b>Test DOM implementation</b>');
	
	testfun('document.write', function() { document.write('hello, world!'); });
	testfun('document.writeln', function() { document.writeln('goodbye, world!'); });
	testfun('document.write (create a node)', function() { document.write('<a id="testa" href="#">this is a new tag</a>'); });
	testfun('document.getElementById (get a node created by document.write)',function () {
		var node;

		document.write('<a id="testa" href="#">this is a new tag</a>');
		node = document.getElementById('testa');
		return sprintf('node.href=%s',node.href);
	});
	testfun('document.createElement p', function() { return document.createElement('p'); });
	testfun('document.createElement p align="center"', function() { 
		var node = document.createElement('p'); 
		node.align = 'center';
	});
	testfun('document.createElement input type="button"', function() {
		var node = document.createElement('input'); 
		node.type = 'button';
		node.value = 123;
		document.body.appendChild(node);
	});
	testfun('document.createElement input type="checkbox"', function() {
		var node = document.createElement('input'); 
		node.type = 'checkbox';
		node.value = 123;
		document.body.appendChild(node);
	});
	testfun('document.createElement input type="radio"', function() {
		var node = document.createElement('input'); 
		node.type = 'radio';
		node.value = 123;
		document.body.appendChild(node);
	});
	testfun('document.createTextNode', function() { return document.createTextNode('Hello, world!'); });
	testfun('document.appendChild', function() {
		var node = document.createTextNode('Hello, world!');
		document.body.appendChild(node);
	});
	testfun('document.getElementsByTagName', function() {
		var nodes = document.getElementsByTagName('p');
		var ret = '';

		ret += sprintf('length=%d',nodes.length);
		for(var i=0;i<nodes.length;i++) ret += sprintf(',item(%d)=%s',i,nodes.item(i));
		return ret;
	});
	testfun('(HTMLElement).innerHTML (get)', function() { return document.getElementById('div1').innerHTML; });
	testfun('(HTMLElement).innerHTML (modify)', function() { document.getElementById('div1').innerHTML = '<b>Hello</b>'; });
	testfun('(HTMLElement).innerHTML (create a new element)', function() {
		var obj = document.getElementById('div1');

		obj.innerHTML = '<table id="newelement1"><tr><td>TD 1</td><td>TD 2</td></tr></table>';
		// try to get back the node
		var tb = document.getElementById('newelement1');
		if(tb) return tb;
		else throw "cannot do that."
	});

	testfun('Behaviour (id same as variable name)', function() {
		div2 = document.getElementById('div2');

		if(div2 && div2.innerHTML == 'div 2') return div2;
		else throw('cannot do that.');
	});
}
function testajax()
{
	output('<b>Test Ajax</b>');

	testfun('ActiveXObject("Msxml2.XMLHTTP5.0")',function() { return new ActiveXObject("Msxml2.XMLHTTP5.0"); });
	testfun('ActiveXObject("Msxml2.XMLHTTP4.0")',function() { return new ActiveXObject("Msxml2.XMLHTTP4.0"); });
	testfun('ActiveXObject("Msxml2.XMLHTTP3.0")',function() { return new ActiveXObject("Msxml2.XMLHTTP3.0"); });
	testfun('ActiveXObject("Msxml2.XMLHTTP2.0")',function() { return new ActiveXObject("Msxml2.XMLHTTP2.0"); });
	testfun('ActiveXObject("Msxml2.XMLHTTP")',function() { return new ActiveXObject("Msxml2.XMLHTTP"); });
	testfun('ActiveXObject("Microsoft.XMLHTTP")',function() { return new ActiveXObject("Microsoft.XMLHTTP"); });
	testfun('XMLHttpRequest()',function() { return new XMLHttpRequest(); });
}
</script>
<body>
<div id="output"></div>
<hr />
<p>Some p 1</p>
<p>Some p 2</p>
<p>Some p 3</p>
<div id="div1">A div</div>
<div id="div2">div 2</div>
</body>
<script>
output('Send message to DIV...ok');
testBase();
testjs();
testDOM();
testajax();
</script>
</html>
